Skip Headers

Oracle® OLAP Developer's Guide to the OLAP API 10g Release 2 (10.2) Part Number B14347-01 |
Home | Book List | Contents | Index | Master Index | Feedback

Previous | Next
| View PDF

# 8 Using a TransactionProvider

This chapter describes the Oracle OLAP API `Transaction` and `TransactionProvider` interfaces and describes how you use implementations of those interfaces in an application. You must create a `TransactionProvider` before you can create a `DataProvider`, and you must use methods of the `TransactionProvider` to prepare and commit a `Transaction` before you can create a `Cursor` for a derived `Source`.

This chapter includes the following topics:

- About Creating a Query in a Transaction

- Using TransactionProvider Objects

For the complete code for the examples in this chapter, see the example programs available from the Overview of the Oracle OLAP Java API Reference.

## About Creating a Query in a Transaction

The Oracle OLAP API is transactional. Each step in creating a query occurs in the context of a `Transaction`. One of the first actions of an OLAP API application is to create a `TransactionProvider`. The `TransactionProvider` provides `Transaction` objects to the application.

The `TransactionProvider` ensures the following:

- A `Transaction` is isolated from other `Transaction` objects. Operations performed in a `Transaction` are not visible in, and do not affect, other `Transaction` objects.

- If an operation in a `Transaction` fails, its effects are undone (the `Transaction` is rolled back).

- The effects of a completed `Transaction` persist.

When you create a derived `Source` by calling a method of another `Source`, the derived `Source` is created in the context of the current `Transaction`. The `Source` is active in the `Transaction` in which you create it or in a child `Transaction` of that `Transaction`.

You get or set the current `Transaction`, or begin a child `Transaction`, by calling methods of a `TransactionProvider`. In a child `Transaction` you can alter the query, for example by changing the selection of dimension elements or by performing a different mathematical or analytical operation on the data, which changes the state of a `Template` that you created in the parent `Transaction`. By displaying the data specified by the `Source` produced by the `Template` in the parent `Transaction` and also displaying the data specified by the `Source` produced by the `Template` in the child `Transaction`, you can provide the end user of your application with the means of easily altering a query and viewing the results of different operations on the same set of data, or the same operations on different sets of data.

### Types of Transaction Objects

The OLAP API has the following two types of `Transaction` objects:

- A read `Transaction`. Initially, the current `Transaction` is a read `Transaction`. A read `Transaction` is required for creating a `Cursor` to fetch data from Oracle OLAP. For more information on `Cursor` objects, see Chapter 10.

- A write `Transaction`. A write `Transaction` is required for creating a derived `Source` or for changing the state of a `Template`. For more information on creating a derived `Source`, see Chapter 6. For information on `Template` objects, see Chapter 11.

In the initial read `Transaction`, if you create a derived `Source` or if you change the state of a `Template` object, then a child write `Transaction` is automatically generated. That child `Transaction` becomes the current `Transaction`.

If you then create another derived `Source` or change the `Template` state again, that operation occurs in the same write `Transaction`. You can create any number of derived `Source` objects, or make any number of `Template` state changes, in that same write `Transaction`. You can use those `Source` objects, or the `Source` produced by the `Template`, to define a complex query.

Before you can create a `Cursor` to fetch the result set specified by a derived `Source`, you must move the `Source` from the child write `Transaction` into the parent read `Transaction`. To do so, you prepare and commit the `Transaction`.

### Preparing and Committing a Transaction

To move a `Source` that you created in a child `Transaction` into the parent read `Transaction`, call the `prepareCurrentTransaction` and `commitCurrentTransaction` methods of the `TransactionProvider`. When you commit a child write `Transaction`, a `Source` you created in the child `Transaction` moves into the parent read `Transaction`. The child `Transaction` disappears and the parent `Transaction` becomes the current `Transaction`. The `Source` is active in the current read `Transaction` and you can therefore create a `Cursor` for it.

The following figure illustrates the process of moving a `Source` created in a child write `Transaction` into its parent read `Transaction`.

Figure 8-1 Committing a Write Transaction into Its Parent Read Transaction

Description of "Figure 8-1 Committing a Write Transaction into Its Parent Read Transaction"

### About Transaction and Template Objects

Getting and setting the current `Transaction`, beginning a child `Transaction`, and rolling back a `Transaction` are operations that you use to allow an end user to make different selections starting from a given state of a dynamic query.

To present the end user with alternatives based on the same initial query, you do the following:

1. Create a `Template` in a parent `Transaction` and set the initial state for the `Template`.

2. Get the `Source` produced by the `Template`, create a `Cursor` to retrieve the result set, get the values from the `Cursor`, and then display the results to the end user.

3. Begin a child `Transaction` and modify the state of the `Template`.

4. Get the `Source` produced by the `Template` in the child `Transaction`, create a `Cursor`, get the values, and display them.

You can then replace the first `Template` state with the second one or discard the second one and retain the first.

### Beginning a Child Transaction

To begin a child read `Transaction`, call the `beginSubtransaction` method of the `TransactionProvider` you are using. In the child read `Transaction`, if you change the state of a `Template`, then a child write `Transaction` begins automatically. The write `Transaction` is a child of the child read `Transaction`.

To get the data specified by the `Source` produced by the `Template`, you prepare and commit the write `Transaction` into its parent read `Transaction`. You can then create a `Cursor` to fetch the data. The changed state of the `Template` is not visible in the original parent. The changed state does not become visible in the parent until you prepare and commit the child read `Transaction` into the parent read `Transaction`.

The following figure illustrates beginning a child read `Transaction`, creating `Source` objects in a write `Transaction`, and committing the write `Transaction` into its parent read `Transaction`. The figure then shows committing the child read `Transaction` into its parent read `Transaction`. In the figure, `tp` is the `TransactionProvider`.

Figure 8-2 Committing a Child Read Transaction into Its Parent Transaction

Description of "Figure 8-2 Committing a Child Read Transaction into Its Parent Transaction"

After beginning a child read `Transaction`, you can begin a child read `Transaction` of that child, or a grandchild of the initial parent `Transaction`. For an example of creating child and grandchild `Transaction` objects, see Example 8-2.

### About Rolling Back a Transaction

You roll back, or undo, a `Transaction` by calling the `rollbackCurrentTransaction` method of the `TransactionProvider` you are using. Rolling back a `Transaction` discards any changes that you made during that `Transaction` and makes the `Transaction` disappear.

Before rolling back a `Transaction`, you must close any `CursorManager` objects you created in that `Transaction`. After rolling back a `Transaction`, any `Source` objects that you created or `Template` state changes that you made in the `Transaction` are no longer valid. Any `Cursor` objects you created for those `Source` objects are also invalid.

Once you roll back a `Transaction`, you cannot prepare and commit that `Transaction`. Likewise, once you commit a `Transaction`, you cannot roll it back.

Example 8-1 Rolling Back a Transaction

The following example uses the `TopBottomTemplate` and `SingleSelectionTemplate` classes that are described in Chapter 11, "Creating Dynamic Queries". In creating the `TopBottomTemplate` and `SingleSelectionTemplate` objects, the example uses the same code that appears in Example 11-4, "Getting the Source Produced by the Template". Example 8-1 does not show that code. This example sets the state of the `TopBottomTemplate`. It begins a child `Transaction` that sets a different state for the `TopBottomTemplate` and then rolls back the child `Transaction`. The `TransactionProvider` is `tp` and `context` is an object that has methods that create `Cursor` objects and display their values.

    // The current Transaction is a read Transaction, t1.
    // Create a TopBottomTemplate using a hierarchy of the Product dimension
    // as the base and dp as the DataProvider.
    TopBottomTemplate topNBottom = new TopBottomTemplate(prodRollup, dp);

    // Changing the state of a Template requires a write Transaction, so a
    // write child Transaction, t2, is automatically started.
    topNBottom.setTopBottomType(TopBottomTemplate.TOP_BOTTOM_TYPE_TOP);
    topNBottom.setN(10);
    topNBottom.setCriterion(singleSelections.getSource());

    // Prepare and commit the Transaction t2.
    try
    {
      tp.prepareCurrentTransaction();
    }
    catch(NotCommittableException e)
    {
      context.println("Cannot commit the Transaction. " + e);
    }
    tp.commitCurrentTransaction();           //t2 disappears

    // The current Transaction is now t1.
    // Get the dynamic Source produced by the TopBottomTemplate.
    Source result = topNBottom.getSource();

    // Create a Cursor and display the results (these operations are
    // performed by the context object).
    context.println("\nThe current state of the TopBottomTemplate\n" +
                    "produces the following values:\n");
    context.displayTopBottomResult(result);

    // Start a child Transaction, t3. It is a read Transaction.
    tp.beginSubtransaction();          // t3 is the current Transaction

    // Change the state of topNBottom. Changing the state requires a
    // write Transaction so Transaction t4 starts automatically,
    topNBottom.setTopBottomType(TopBottomTemplate.TOP_BOTTOM_TYPE_BOTTOM);
    topNBottom.setN(15);

    // Prepare and commit the Transaction.
    try
    {
      tp.prepareCurrentTransaction();
    }
    catch(NotCommittableException e)
    {
      context.println("Cannot commit the Transaction. " + e);
    }
    tp.commitCurrentTransaction();           // t4 disappears

    // Create a Cursor and display the results. // t3 is the current Transaction
    context.println("\nIn the child Transaction, the state of the\n" +
                    "TopBottomTemplate produces the following values:\n");
    context.displayTopBottomResult(result);
    // The displayTopBottomResult method closes the CursorManager for the
    // Cursor created in t3.

    // Undo t3, which discards the state of topNBottom that was set in t4.
    tp.rollbackCurrentTransaction();        // t3 disappears

    // Transaction t1 is now the current Transaction and the state of
    // topNBottom is the one defined in t2.

    // To show the current state of the TopNBottom template Source,
    // prepare and commit the Transaction, create a Cursor, and display
    // its values.
    try
    {
      tp.prepareCurrentTransaction();
    }
    catch(NotCommittableException e)
    {
      context.println("Cannot commit the Transaction. " + e);
    }
    tp.commitCurrentTransaction();

    context.println("\nAfter rolling back the child Transaction, the state "
    + "of\nthe TopBottomTemplate produces the following "
    + "values:\n");
    context.displayTopBottomResult(result);

Example 8-1 produces the following output.

    The current state of the TopBottomTemplate
    produces the following values:

    1. PRODUCT_ROLLUP::TOTAL_PRODUCT::1
    2. PRODUCT_ROLLUP::CLASS::3
    3. PRODUCT_ROLLUP::FAMILY::7
    4. PRODUCT_ROLLUP::CLASS::2
    5. PRODUCT_ROLLUP::FAMILY::9
    6. PRODUCT_ROLLUP::FAMILY::6
    7. PRODUCT_ROLLUP::FAMILY::11
    8. PRODUCT_ROLLUP::ITEM::30
    9. PRODUCT_ROLLUP::ITEM::28
    10. PRODUCT_ROLLUP::ITEM::47

    In the child Transaction, the state of the
    TopBottomTemplate produces the following values:

    1. PRODUCT_ROLLUP::ITEM::36
    2. PRODUCT_ROLLUP::ITEM::43
    3. PRODUCT_ROLLUP::ITEM::44
    4. PRODUCT_ROLLUP::ITEM::38
    5. PRODUCT_ROLLUP::ITEM::22
    6. PRODUCT_ROLLUP::ITEM::21
    7. PRODUCT_ROLLUP::ITEM::42
    8. PRODUCT_ROLLUP::ITEM::41
    9. PRODUCT_ROLLUP::ITEM::15
    10. PRODUCT_ROLLUP::ITEM::34
    11. PRODUCT_ROLLUP::ITEM::14
    12. PRODUCT_ROLLUP::ITEM::45
    13. PRODUCT_ROLLUP::ITEM::13
    14. PRODUCT_ROLLUP::ITEM::26
    15. PRODUCT_ROLLUP::ITEM::18

    After rolling back the child Transaction, the state of
    the TopBottomTemplate produces the following values:

    1. PRODUCT_ROLLUP::TOTAL_PRODUCT::1
    2. PRODUCT_ROLLUP::CLASS::3
    3. PRODUCT_ROLLUP::FAMILY::7
    4. PRODUCT_ROLLUP::CLASS::2
    5. PRODUCT_ROLLUP::FAMILY::9
    6. PRODUCT_ROLLUP::FAMILY::6
    7. PRODUCT_ROLLUP::FAMILY::11
    8. PRODUCT_ROLLUP::ITEM::30
    9. PRODUCT_ROLLUP::ITEM::28
    10. PRODUCT_ROLLUP::ITEM::47

### Getting and Setting the Current Transaction

You get the current `Transaction` by calling the `getCurrentTransaction` method of the `TransactionProvider` you are using, as in the following example.

    Transaction t1 = getCurrentTransaction();

To make a previously saved `Transaction` the current `Transaction`, you call the `setCurrentTransaction` method of the `TransactionProvider`, as in the following example.

    setCurrentTransaction(t1);

## Using TransactionProvider Objects

``In the Oracle OLAP API, the `TransactionProvider` interface is implemented by the `ExpressTransactionProvider` concrete class. Before you create a `DataProvider`, you must create a new instance of an `ExpressTransactionProvider`. You then pass that `TransactionProvider` to the `DataProvider` constructor. The `TransactionProvider` provides `Transaction` objects to your application.

As described in "Preparing and Committing a Transaction", you use the `prepareCurrentTransaction` and `commitCurrentTransaction` methods to make a derived `Source` that you created in a child write `Transaction` visible in the parent read `Transaction`. You can then create a `Cursor` for that `Source`.

If you are using `Template` objects in your application, then you might also use the other methods of `TransactionProvider` to do the following:

- Begin a child `Transaction`.

- Get the current `Transaction` so you can save it.

- Set the current `Transaction` to a previously saved one.

- Rollback, or undo, the current `Transaction`, which discards any changes made in the `Transaction`. Once a `Transaction` has been rolled back, it is invalid and cannot be committed. Once a `Transaction` has been committed, it cannot be rolled back. If you created a `Cursor` for a `Source` in a `Transaction`, you must close the `CursorManager` before rolling back the `Transaction`.

Example 8-2 demonstrates the use of `Transaction` objects to modify dynamic queries. Like Example 8-1, this example uses the same code to create `TopBottomTemplate` and `SingleSelectionTemplate` objects as does Example 11-4, "Getting the Source Produced by the Template". This example does not show that code.

To help track the `Transaction` objects, this example saves the different `Transaction` objects with calls to the `getCurrentTransaction` method. In the example, `tp` object is the `TransactionProvider`, and `context` is an object that has methods that create `Cursor` objects and display their values.

Example 8-2 Using Child Transaction Objects

    // The parent Transaction is the current Transaction at this point.
    // Save the parent read Transaction as parentT1.
    Transaction parentT1 = tp.getCurrentTransaction();

    // Get the dynamic Source produced by the TopBottomTemplate.
    Source result = topNBottom.getSource();

    // Create a Cursor and display the results (these operations are
    // performed by the context object).
    context.println("\nThe current state of the TopBottomTemplate\n" +
                    "produces the following values:\n");
    context.displayTopBottomResult(result);

    // Begin a child Transaction of parentT1.
    tp.beginSubtransaction();  // This is a read Transaction.

    // Save the child read Transaction as childT2.
    Transaction childT2 = tp.getCurrentTransaction();

    // Change the state of the TopBottomTemplate. This starts a
    // write Transaction, a child of the read Transaction childT2.
    topNBottom.setN(12);
    topNBottom.setTopBottomType(TopBottomTemplate.TOP_BOTTOM_TYPE_BOTTOM);

    // Save the child write Transaction as writeT3.
    Transaction writeT3 = tp.getCurrentTransaction();

    // Prepare and commit the write Transaction writeT3.
    try
    {
      tp.prepareCurrentTransaction();
    }
    catch(NotCommittableException e)
    {
      context.println("Cannot commit current Transaction. " + e);
    }
    tp.commitCurrentTransaction();

    // The commit moves the changes made in writeT3 into its parent,
    // the read Transaction childT2. The writeT3 Transaction
    // disappears. The current Transaction is now childT2
    // again but the state of the TopBottomTemplate has changed.

    // Create a Cursor and display the results of the changes to the
    // TopBottomTemplate that are visible in childT2.
    try
    {
      context.println("\nIn the child Transaction, the state of the\n" +
                      "TopBottomTemplate produces the following values:\n");

      context.displayTopBottomResult(result);
    }
    catch(Exception e)
    {
      context.println("Cannot display the results of the query. " + e);
    }

    // Begin a grandchild Transaction of the initial parent.
    tp.beginSubtransaction();  // This is a read Transaction.

    // Save the grandchild read Transaction as grandchildT4.
    Transaction grandchildT4 = tp.getCurrentTransaction();

    // Change the state of the TopBottomTemplate. This starts another
    // write Transaction, a child of grandchildT4.
    topNBottom.setTopBottomType(TopBottomTemplate.TOP_BOTTOM_TYPE_TOP);

    // Save the write Transaction as writeT5.
    Transaction writeT5 = tp.getCurrentTransaction();

    // Prepare and commit writeT5.
    try
    {
      tp.prepareCurrentTransaction();
    }
    catch(NotCommittableException e)
    {
      context.println("Cannot commit current Transaction. " + e);
    }
    tp.commitCurrentTransaction();

    // Transaction grandchildT4 is now the current Transaction and the
    // changes made to the TopBottomTemplate state are visible.

    // Create a Cursor and display the results visible in grandchildT4.
    try
    {
      context.println("\nIn the grandchild Transaction, the state of the\n" +
                      "TopBottomTemplate produces the following values:\n");
      context.displayTopBottomResult(result);
    }
    catch(Exception e)
    {
      context.println(""Cannot display the results of the query. " + e);
    }

    // Commit the grandchild into the child.
    try
    {
      tp.prepareCurrentTransaction();
    }
    catch(NotCommittableException e)
    {
      context.println("Cannot commit current Transaction. " + e);
    }
    tp.commitCurrentTransaction();

    // Transaction childT2 is now the current Transaction.
    // Instead of preparing and committing the grandchild Transaction,
    // you could rollback the Transaction, as in the following
    // method call:
    //   rollbackCurrentTransaction();
    // If you roll back the grandchild Transaction, then the changes
    // you made to the TopBottomTemplate state in the grandchild
    // are discarded and childT2 is the current Transaction.

    // Commit the child into the parent.
    try
    {
      tp.prepareCurrentTransaction();
    }
    catch(NotCommittableException e)
    {
      context.println("Cannot commit the child Transaction. " + e);
    }
    tp.commitCurrentTransaction();

    // Transaction parentT1 is now the current Transaction. Again,
    // you can roll back the childT2 Transaction instead of
    // preparing and committing it. If you do so, then the changes
    // you made in childT2 are discarded. The current Transaction
    // is be parentT1, which has the original state of
    // the TopBottomTemplate, without any of the changes made in
    // the grandchild or the child transactions.

Example 8-2 produces the following output.

    The current state of the TopBottomTemplate
    produces the following values:

    1. PRODUCT_ROLLUP::TOTAL_PRODUCT::1
    2. PRODUCT_ROLLUP::CLASS::3
    3. PRODUCT_ROLLUP::FAMILY::7
    4. PRODUCT_ROLLUP::CLASS::2
    5. PRODUCT_ROLLUP::FAMILY::9
    6. PRODUCT_ROLLUP::FAMILY::6
    7. PRODUCT_ROLLUP::FAMILY::11
    8. PRODUCT_ROLLUP::ITEM::30
    9. PRODUCT_ROLLUP::ITEM::28
    10. PRODUCT_ROLLUP::ITEM::47

    In the child Transaction, the state of the
    TopBottomTemplate produces the following values:

    1. PRODUCT_ROLLUP::ITEM::36
    2. PRODUCT_ROLLUP::ITEM::43
    3. PRODUCT_ROLLUP::ITEM::44
    4. PRODUCT_ROLLUP::ITEM::38
    5. PRODUCT_ROLLUP::ITEM::22
    6. PRODUCT_ROLLUP::ITEM::21
    7. PRODUCT_ROLLUP::ITEM::42
    8. PRODUCT_ROLLUP::ITEM::41
    9. PRODUCT_ROLLUP::ITEM::15
    10. PRODUCT_ROLLUP::ITEM::34
    11. PRODUCT_ROLLUP::ITEM::14
    12. PRODUCT_ROLLUP::ITEM::45

    In the grandchild Transaction, the state of the
    TopBottomTemplate produces the following values:

    1. PRODUCT_ROLLUP::TOTAL_PRODUCT::1
    2. PRODUCT_ROLLUP::CLASS::3
    3. PRODUCT_ROLLUP::FAMILY::7
    4. PRODUCT_ROLLUP::CLASS::2
    5. PRODUCT_ROLLUP::FAMILY::9
    6. PRODUCT_ROLLUP::FAMILY::6
    7. PRODUCT_ROLLUP::FAMILY::11
    8. PRODUCT_ROLLUP::ITEM::30
    9. PRODUCT_ROLLUP::ITEM::28
    10. PRODUCT_ROLLUP::ITEM::47
    11. PRODUCT_ROLLUP::ITEM::19
    12. PRODUCT_ROLLUP::ITEM::24